/*
 * iic.c
 *
 *  Created on: 2014-3-9
 *      Author: Rome
 */


#include"string.h"
#include <stdio.h>
#include <unistd.h>
#include "altera_avalon_pio_regs.h"
#include "system.h"
#include "time.h"
#define DELAY_TIME 3
#define Set_SDA  IOWR_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE, 0x1)
#define Clr_SDA  IOWR_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE, 0x0)
#define Set_SCL  IOWR_ALTERA_AVALON_PIO_DATA(I2C_SCL_BASE, 0x1)
#define Clr_SCL  IOWR_ALTERA_AVALON_PIO_DATA(I2C_SCL_BASE, 0x0)

void I2C_Start(void)
{ /*
      SDA -------_________
      SCL ------------____
*/
  //????
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x1);
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
  //SDA = 1
  //SCL = 1
  Set_SDA;
  Set_SCL;
  usleep(DELAY_TIME);
  //SDA = 0
  //SCL = 1
  Clr_SDA;
  usleep(DELAY_TIME);
  //SDA = 0
  //SCL = 0
  Clr_SCL;
  usleep(DELAY_TIME);
}

void I2C_Stop(void)
{ /*
      SDA _________--------
      SCL ____-------------
*/
  //????
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x1);
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
  //SDA = 0
  //SCL = 0
  Clr_SDA;
  Clr_SCL;
  usleep(DELAY_TIME);
  //SDA = 0
  //SCL = 1
  Clr_SDA;
  Set_SCL;
  usleep(DELAY_TIME);
  //SDA = 1
  //SCL = 1
  Set_SDA;
  usleep(DELAY_TIME);
}

void I2C_Ack(void)//?????
{  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x1);
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
  Clr_SDA;
  usleep(DELAY_TIME);
  Set_SCL;
  usleep(DELAY_TIME);
  //while(IORD_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE)){;};
  Clr_SCL;
  usleep(DELAY_TIME);
}
void Check_Ack(void)
{ char a=1;
  // SDA = "Z"
  // SCL = 0
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x0);
  //IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
  Clr_SCL;
  usleep(DELAY_TIME);
  // SCL = 1
  Set_SCL;
  usleep(DELAY_TIME);
  while(a)
   {
     a=IORD_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE);
     usleep(DELAY_TIME);
//     printf("waiting ACK a is %d\n",a);
   }
  usleep(DELAY_TIME);//
//  printf("detected ACK\n");
  Clr_SCL;
  usleep(DELAY_TIME);
}

void I2C_Nack(void)//?????
{ IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x1);
  IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
  Set_SDA;
  usleep(DELAY_TIME);
  Set_SCL;
  usleep(DELAY_TIME);
  Clr_SCL;
  usleep(DELAY_TIME);
}

void I2C_Send_Byte(char d)
{
unsigned char i = 8;
IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x1);
IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
usleep(DELAY_TIME);

/*
                    MSB
    SDA  ______-------------__________

    SCL  _________-------_____________

 */

   Clr_SDA;
   Clr_SCL;
   usleep(DELAY_TIME);

while( i-- )
  {

    if (d&0x80)
        Set_SDA;
    else
        Clr_SDA;
    usleep(DELAY_TIME);

       Set_SCL;
    usleep(DELAY_TIME);
       Clr_SCL;
    usleep(DELAY_TIME);

    //SCL = 0
    //SDA = 0
      Clr_SDA;
      Clr_SCL;
    usleep(DELAY_TIME);

    d = d << 1;
   }
usleep(DELAY_TIME);

}


unsigned char I2C_Receive_Byte(void)
{
	unsigned char rn = 8, data=0,rr=0x80;
	IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SDA_BASE, 0x0);
	IOWR_ALTERA_AVALON_PIO_DIRECTION(I2C_SCL_BASE, 0x1);
	usleep(DELAY_TIME);
	for(;rn!=0;rn--)
	{
	Set_SCL;
	usleep(DELAY_TIME);
	if (IORD_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE))
	data|=rr;
	//printf("IORD_ALTERA_AVALON_PIO_DATA",IORD_ALTERA_AVALON_PIO_DATA(I2C_SDA_BASE));
	else
	data&=~rr;
	rr>>=1;
	 Clr_SCL;
	usleep(DELAY_TIME);
	}
	//printf("I2C_Receive_Byte is %x\n",data);
	return data;
}

void AT24C16_W(unsigned short address, unsigned char ddata )
{
	alt_u8 cmd;

	alt_u8 addr_local;

	cmd = (0xa0 | (address >> 7)) & 0xfe;
	addr_local = address & 0xFF;

	I2C_Start();
	I2C_Send_Byte(cmd);
	Check_Ack();
	I2C_Send_Byte(addr_local);
	Check_Ack();
	I2C_Send_Byte(ddata);
	Check_Ack();
	//printf("write data\n");
	I2C_Stop();
	usleep(50000);
}

unsigned char AT24C16_R(unsigned short address)
{
	unsigned char rdata;
	alt_u8 cmd;

	alt_u8 addr_local;

	cmd = (0xa0 | (address >> 7)) & 0xfe;
	addr_local = address & 0xFF;

	I2C_Start();
	I2C_Send_Byte( cmd );
	Check_Ack();
	I2C_Send_Byte( addr_local );
	Check_Ack();
	I2C_Start();
	cmd = (0xa0 | (address >> 7)) | 0x01;
	I2C_Send_Byte( cmd );
	Check_Ack();
	rdata=I2C_Receive_Byte();
	I2C_Nack();
	I2C_Stop();
	return rdata;
}

